home *** CD-ROM | disk | FTP | other *** search
- /* User calls to TCP */
- #include "machdep.h"
- #include "timer.h"
- #include "mbuf.h"
- #include "netuser.h"
- #include "internet.h"
- #include "ip.h"
- #include "tcp.h"
-
- int16 tcp_window = DEF_WND;
-
- struct tcb *
- open_tcp(lsocket,fsocket,active,window,r_upcall,t_upcall,s_upcall,tos,user)
- struct socket *lsocket; /* Local socket */
- struct socket *fsocket; /* Remote socket */
- int active; /* Active/passive */
- int16 window; /* Receive window (and send buffer) sizes */
- void (*r_upcall)(); /* Function to call when data arrives */
- void (*t_upcall)(); /* Function to call when ok to send more data */
- void (*s_upcall)(); /* Function to call when connection state changes */
- char tos;
- int *user; /* User linkage area */
- {
- struct connection conn;
- register struct tcb *tcb;
- void send_syn();
-
- if(lsocket == NULLSOCK){
- net_error = INVALID;
- return NULLTCB;
- }
- conn.local.address = lsocket->address;
- conn.local.port = lsocket->port;
- if(fsocket != NULLSOCK){
- conn.remote.address = fsocket->address;
- conn.remote.port = fsocket->port;
- } else {
- conn.remote.address = 0;
- conn.remote.port = 0;
- }
- if((tcb = lookup_tcb(&conn)) == NULLTCB){
- if((tcb = create_tcb(&conn)) == NULLTCB){
- net_error = NO_SPACE;
- return NULLTCB;
- }
- } else if(tcb->state != LISTEN){
- net_error = CON_EXISTS;
- return NULLTCB;
- }
- tcb->user = user;
- if(window != 0)
- tcb->window = tcb->rcv.wnd = window;
- else
- tcb->window = tcb->rcv.wnd = tcp_window;
- tcb->r_upcall = r_upcall;
- tcb->t_upcall = t_upcall;
- tcb->s_upcall = s_upcall;
- tcb->tos = tos;
- if(!active){
- setstate(tcb,LISTEN);
- return tcb;
- }
- /* Send SYN, go into SYN_SENT state */
- send_syn(tcb);
- setstate(tcb,SYN_SENT);
- tcp_output(tcb);
- tcp_stat.conout++;
- return tcb;
- }
- /* User send routine */
- int
- send_tcp(tcb,bp)
- register struct tcb *tcb;
- struct mbuf *bp;
- {
- int16 cnt;
-
- if(tcb == NULLTCB || bp == NULLBUF){
- free_p(bp);
- net_error = INVALID;
- return -1;
- }
- cnt = len_mbuf(bp);
- #ifdef TIGHT
- /* If this would overfill our send queue, reject it entirely */
- if(tcb->sndcnt + cnt > tcb->window){
- free_p(bp);
- net_error = WOULDBLK;
- return -1;
- }
- #endif
- switch(tcb->state){
- case CLOSED:
- free_p(bp);
- net_error = NO_CONN;
- return -1;
- case LISTEN: /* Change state from passive to active */
- send_syn(tcb);
- setstate(tcb,SYN_SENT); /* Note fall-thru */
- case SYN_SENT:
- case SYN_RECEIVED:
- case ESTABLISHED:
- case CLOSE_WAIT:
- append(&tcb->sndq,bp);
- tcb->sndcnt += cnt;
- tcp_output(tcb);
- break;
- case FINWAIT1:
- case FINWAIT2:
- case CLOSING:
- case LAST_ACK:
- case TIME_WAIT:
- free_p(bp);
- net_error = CON_CLOS;
- return -1;
- }
- return cnt;
- }
- /* User receive routine */
- int
- recv_tcp(tcb,bp,cnt)
- register struct tcb *tcb;
- struct mbuf **bp;
- int16 cnt;
- {
- if(tcb == NULLTCB || bp == (struct mbuf **)NULL){
- net_error = INVALID;
- return -1;
- }
- /* cnt == 0 means "I want it all" */
- if(cnt == 0)
- cnt = tcb->rcvcnt;
- /* If there's something on the queue, just return it regardless
- * of the state we're in.
- */
- if(tcb->rcvcnt != 0){
- /* See if the user can take all of it */
- if(tcb->rcvcnt <= cnt){
- cnt = tcb->rcvcnt;
- *bp = tcb->rcvq;
- tcb->rcvq = NULLBUF;
- } else {
- if((*bp = alloc_mbuf(cnt)) == NULLBUF){
- net_error = NO_SPACE;
- return -1;
- }
- pullup(&tcb->rcvq,(*bp)->data,cnt);
- (*bp)->cnt = cnt;
- }
- tcb->rcvcnt -= cnt;
- tcb->rcv.wnd += cnt;
- /* Do a window update if it was closed */
- if(cnt == tcb->rcv.wnd){
- tcb->force = 1;
- tcp_output(tcb);
- }
- return cnt;
- } else {
- /* If there's nothing on the queue, our action depends on what state
- * we're in (i.e., whether or not we're expecting any more data).
- * If no more data is expected, then simply return 0; this is
- * interpreted as "end of file".
- */
- switch(tcb->state){
- case LISTEN:
- case SYN_SENT:
- case SYN_RECEIVED:
- case ESTABLISHED:
- case FINWAIT1:
- case FINWAIT2:
- *bp = NULLBUF;
- net_error = WOULDBLK;
- return -1;
- case CLOSED:
- case CLOSE_WAIT:
- case CLOSING:
- case LAST_ACK:
- case TIME_WAIT:
- *bp = NULLBUF;
- return 0;
- }
- }
- return 0; /* Not reached, but lint doesn't know that */
- }
- /* This really means "I have no more data to send". It only closes the
- * connection in one direction, and we can continue to receive data
- * indefinitely.
- */
- int
- close_tcp(tcb)
- register struct tcb *tcb;
- {
- if(tcb == NULLTCB){
- net_error = INVALID;
- return -1;
- }
- switch(tcb->state){
- case LISTEN:
- case SYN_SENT:
- close_self(tcb,NORMAL);
- return 0;
- case SYN_RECEIVED:
- case ESTABLISHED:
- tcb->sndcnt++;
- tcb->snd.nxt++;
- setstate(tcb,FINWAIT1);
- tcp_output(tcb);
- return 0;
- case CLOSE_WAIT:
- tcb->sndcnt++;
- tcb->snd.nxt++;
- setstate(tcb,LAST_ACK);
- tcp_output(tcb);
- return 0;
- case FINWAIT1:
- case FINWAIT2:
- case CLOSING:
- case LAST_ACK:
- case TIME_WAIT:
- net_error = CON_CLOS;
- return -1;
- }
- return -1; /* "Can't happen" */
- }
- /* Delete TCB, free resources. The user is not notified, even if the TCB is
- * not in the CLOSED state. This function should normally be called by the
- * user only in response to a state change upcall to CLOSED state.
- */
- int
- del_tcp(tcb)
- register struct tcb *tcb;
- {
- void unlink_tcb();
- struct reseq *rp,*rp1;
-
- if(tcb == NULLTCB){
- net_error = INVALID;
- return -1;
- }
- unlink_tcb(tcb);
- stop_timer(&tcb->timer);
- for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
- rp1 = rp->next;
- free_p(rp->bp);
- free((char *)rp);
- }
- tcb->reseq = NULLRESEQ;
- free_p(tcb->rcvq);
- free_p(tcb->sndq);
- free((char *)tcb);
- return 0;
- }
- /* Do printf on a tcp connection */
- /*VARARGS*/
- tprintf(tcb,message,arg1,arg2)
- struct tcb *tcb;
- char *message,*arg1,*arg2;
- {
- struct mbuf *bp;
- int16 len;
- char *cp,*index();
-
- if(tcb == NULLTCB)
- return 0;
-
- len = strlen(message) + 10; /* fudge factor */
- if((cp = index(message,'%')) != NULLCHAR){
- /* What a gross hack! */
- len += strlen(arg1);
- if((cp = index(cp+1,'%')) != NULLCHAR){
- /* I don't believe I'm writing this */
- len += strlen(arg2);
- }
- }
- bp = alloc_mbuf(len);
- len = sprintf(bp->data,message,arg1,arg2);
- bp->cnt = strlen(bp->data);
- send_tcp(tcb,bp);
- return len;
- }
-